import csv
import datetime
import os
import random
import shutil
import smtplib
import time
import zipfile
from email import encoders  # 转码
from email.mime.base import MIMEBase  # 附件
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText  # 文本

import pandas as pd
from matplotlib import pyplot as plt
import numpy as np
import pymysql
import qrcode
from PIL import Image, ImageDraw, ImageFont
from flask import Flask, redirect, render_template, request, session, flash, url_for
from werkzeug.utils import secure_filename

from Python_Course_Design.DataBase_init import get_user_info

# 每日功能使用 计数
today = str(datetime.date.today())[-5:]  # 原获取的格式为 2020-09-24，转换str类型，切片处理成09-24
# FlaskWeb.py当前路径(os.getcwd()只能返回当前Project的路径，即'Python代码存放')
now_path = os.getcwd() + '\\Python_Course_Design'
# 默认的文件下载位置
UPLOAD_FOLDER = '\\static\\uploads'
# 被允许的文件类型
ALLOWED_EXTENSIONS = {'txt', 'csv', 'xlsx'}
# 连接数据库
user_info = get_user_info('bcgs_db', 'root', '123', 'accountInfo')
# 创建flask对象
app = Flask(__name__, template_folder='templates')
# flask自动更新代码
app.debug = True
# 签名加密，防止从network中看到密码
app.secret_key = 'asd2asd2asd3'
# 设置存储上传的文件的位置
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
dir_name = ''
user_name = ''


# 生成二维码
def qr_code(data):
    """
    :param data:原图片
    :return:生成的二维码图片
    """
    # 自定义二维码
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_L,
        box_size=3
    )
    qr.add_data(data)
    qr.make(fit=True)
    img = qr.make_image(fill_color="black", back_color='white')
    return img


# 下载文件是否符合限制要求
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS


# 移动文件
def move_file(old_file, new_file):
    """
    :param old_file: 文件原位置
    :param new_file: 移动到的目标位置
    :return: null
    """
    if not os.path.isfile(old_file):
        print("%s不在该路径内路径异常！" % old_file)
    else:
        path, file_name = os.path.split(new_file)  # 分离文件名和路径
        if not os.path.exists(path):
            os.makedirs(path)  # 创建路径
        shutil.move(old_file, new_file)  # 移动文件
        # print("move %s -> %s" % (old_file, new_file))


# 用程序运行时间为文件夹名，在当前路径下的static文件夹新建文件夹
def new_time_dir():
    """
    :return: 以当前时间命名的文件夹名
    """
    dir_time = time.strftime('%Y-%m-%d %Hh%Mm%Ss', time.localtime(time.time()))
    if not os.path.exists(dir_time):
        # 当前路径下新建用mkdir，其他路径要用makedirs
        os.makedirs(f'{now_path}\\static\\uploads\\{dir_time}')
    else:
        print('当前时间的文件夹已存在')
    return dir_time


# 废除，不可用
# folderPath: 文件路径  compressPathName: 压缩包路径
def zip_file(folder_path, compress_path_name):
    """
    :param folder_path: 渴望被压缩的文件，路径+文件名
    :param compress_path_name: 被压榨完的文件位置，路径+文件名 且.zip结尾
    :return: null
    """
    z = zipfile.ZipFile(compress_path_name, 'w', zipfile.ZIP_DEFLATED)
    # dict = {}
    for path, dirNames, fileNames in os.walk(folder_path):
        f_path = path.replace(folder_path, '')
        for name in fileNames:
            full_name = os.path.join(path, name).decode(encoding='gbk')

            name = f_path + '\\' + name
            z.write(full_name, name)
    z.close()


# 对目录进行深度优先遍历
def get_zip_file(input_path, result):
    """
    :param input_path:
    :param result:
    :return:
    """
    files = os.listdir(input_path)
    for file in files:
        if os.path.isdir(input_path + '/' + file):
            get_zip_file(input_path + '/' + file, result)
        else:
            result.append(input_path + '/' + file)


# 压缩文件
def zip_file_path(input_path, output_path, output_name):
    """
    :param input_path: 压缩的文件夹路径
    :param output_path: 解压（输出）的路径
    :param output_name: 压缩包名称
    :return:
    """
    f = zipfile.ZipFile(output_path + '/' + output_name, 'w', zipfile.ZIP_DEFLATED)
    file_lists = []
    get_zip_file(input_path, file_lists)
    for file in file_lists:
        f.write(file)
    # 调用了close方法才会保证完成压缩
    f.close()
    return output_path + r"/" + output_name


# 生成用户奖状的函数（后面需要改，增加图片的选择）
def poster_name(msg, model=f"{now_path}/static/images/index/model_1.png", image_font="simkai.ttf",
                draw_color="#000"):
    img_name = Image.open(model)
    # 创建画刷
    draw = ImageDraw.Draw(img_name)
    # 设置字体
    font = ImageFont.truetype(image_font, 30)
    color = draw_color

    # 写上学员的姓名(根据名字长短来不同定位，保持不偏离)
    if len(msg) == 5:
        draw.text((173, 260), msg, fill=color, font=font)
    elif len(msg) == 6:
        draw.text((153, 260), msg, fill=color, font=font)
    elif len(msg) == 7:
        draw.text((133, 260), msg, fill=color, font=font)
    else:
        draw.text((93, 260), msg, fill=color, font=font)

    # # 生成二维码
    # img_qr_code = qr_code(file_name)
    # # 将生成的二维码粘贴在原图上
    # area = (33, 493, 120, 580)
    # img_name.paste(img_qr_code, area)
    # img_name.show()
    img_name.save(f'{msg}.png')

    # 将图片移动至文件夹
    move_file(f'{msg}.png', f'{now_path}\\static\\uploads\\{dir_name}\\{msg}.png')


# 邮件服务器基础设置
def server_init(msg):
    """
    :param msg: 邮件数据
    :return: null
    """
    host = 'smtp.qq.com'
    server = smtplib.SMTP(host)
    server.starttls()
    from_addr = 'zhuming-self@qq.com'  # 发件人
    my_pass = 'codxbqbhsxmteafh'  # QQ邮箱的授权码
    server.login(from_addr, my_pass)
    server.send_message(msg)
    server.quit()


# 邮件形式发送当前时间的压缩包
def send_listing(mail_to):
    """
    :return: null
    """
    # global msg_list
    msg_list = MIMEMultipart()
    msg_list['From'] = 'zhuming-self@qq.com'
    msg_list['To'] = mail_to
    msg_list['Subject'] = '叮叮！批量生成奖状系统发文件来啦！'  # 邮件的标题
    body = f'您于{dir_name}使用系统，本次邮件是导出的压缩包，请查收！'  # 邮件主要内容
    msg_list.attach(MIMEText(body))
    # 添加附件
    with open(f"{now_path}\\static\\uploads\\{dir_name}.zip", 'rb') as f:
        # 这里附件的MIME和文件名，这里是xls类型
        mime = MIMEBase('zip', 'zip', filename=f'{dir_name}.zip')
        # 加上必要的头信息
        mime.add_header('Content-Disposition', 'attachment', filename=('gb2312', '', f'{dir_name}.zip'))
        mime.add_header('Content-ID', '<0>')
        mime.add_header('X-Attachment-Id', '0')
        # 把附件的内容读进来
        mime.set_payload(f.read())
        # 用Base64编码
        encoders.encode_base64(mime)
        msg_list.attach(mime)
    server_init(msg_list)
    print(">>>发送邮件成功！")


def jpg_generate():
    """
    :return: null
    """
    # 设置图片大小
    fig = plt.figure(figsize=(19.20, 10.80), dpi=80)
    # 设置中文显示
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['font.family'] = 'sans-serif'
    date_list = ['09-30', '10-01', '10-02', '10-03', '10-04',
                 '10-05', '10-06', '10-07', '10-08', '10-09', ]
    random_list = random.choices(range(10, 96), k=10, weights=range(10, 96))
    day_count = []
    for i in range(len(date_list)):
        day_count.append([date_list[i], random_list[i]])

    date_count = np.array(day_count)
    x = date_count[:, 0]
    y = [int(x) for x in date_count[-10:, 1]]
    # 绘图
    plt.plot(x, y, color="#0eacf0", linewidth=5, alpha=0.5)
    # 调整x轴刻度
    plt.xticks(x[-10::1], rotation=40)
    # 添加描述信息
    plt.xlabel("日期", fontsize=20)
    plt.ylabel("数量", fontsize=20)
    plt.title("批量生成奖状系统每日生成个数统计折线图", fontsize=24)
    # 绘制网格
    plt.grid(alpha=0.4, linestyle=":")  # 设置透明度 0-1,越大越清晰
    # 文件存在即删除
    if os.path.isfile('static/images/the_account.png'):
        os.remove('static/images/the_account.png')
    # 保存图片到本地
    plt.savefig('static/images/the_account.png')


# 登录界面
@app.route('/', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template("login.html")
    else:
        # request get到的数据形成元组，方便后面判断
        user = request.form.get('user')
        pwd = request.form.get('pwd')
        get_data = (user, pwd)
        # 只要在遍历数据库的大元组里面，就通过
        if get_data in user_info:
            global user_name
            # 获取用户名
            user_name = user
            # 用户信息放入session
            session['user_info'] = user
            # 跳转到index.html
            return redirect('/index.html')
        else:
            return render_template('login.html', msg='用户名或密码错误!')


@app.route('/index.html', methods=['GET', 'POST'])
def index():
    # 获取session的user_info的值，若为null则回到到login.html
    temp = session.get('user_info')
    if not temp:
        return redirect(url_for('/'))
    else:
        if request.method == 'GET':
            if user_name != '':
                return render_template('index.html', username=f'{user_name}')
            else:
                return render_template('index.html', username='未知用户')
        else:
            # 先用当前时间创建文件夹
            global dir_name, xlsx_list
            dir_name = new_time_dir()
            print('文件夹创建成功')

            # 获取用户提交的邮箱
            user_email = request.form.get('email')
            # 获取
            # model = request.form.get('model')

            # 下载用户上传文件
            # 官：check if the post request has the file part
            if 'file' not in request.files:
                flash('No file part')
                print('request数据中没有file')
                return redirect(request.url)
            file = request.files['file']
            # 官：if user does not select file, browser also
            # 官：submit an empty part without filename
            if file.filename == '':
                flash('file名为空')
                print('file名为空')
                return redirect(request.url)
            if file and allowed_file(file.filename):
                # flask提供的保护文件名函数
                filename = secure_filename(file.filename)
                file.save(f'{now_path}\\static\\uploads\\{today}_{filename}')
            print('前端数据获取完成')

            # 读取文件中的数据
            temp = -1
            if file.filename.rsplit('.', 1)[1].lower() == 'txt':
                temp = 0
                print('当前文档是txt')
                with open(f'{now_path}\\static\\uploads\\{today}_{file.filename}',
                          encoding='utf-8') as f:
                    data = f.readlines()
                    names = data[0].split('、')
                    goals = data[1].split('、')
                    # 处理回车符
                    names[-1] = names[-1][:-1]
                    txt_list = []
                    for num in range(len(names)):
                        txt_list.append(names[num] + ' ' + goals[num])
                    # txt_list格式一般为['name goal', '', '', '']

            elif file.filename.rsplit('.', 1)[1].lower() == 'csv':
                temp = 1
                print('当前文档是csv')
                with open(f'{now_path}\\static\\uploads\\{today}_{file.filename}',
                          encoding='utf-8') as f:
                    reader = csv.reader(f)
                    csv_list = []
                    for line in reader:
                        csv_list.append(f'{line[0]} {line[1]}')
                    # 针对乱码的切片问题
                    csv_list[0] = csv_list[0][1:]
                    # csv_list格式一般为['', '', '', '']
            elif file.filename.rsplit('.', 1)[1].lower() == 'xlsx':
                temp = 2
                print('当前文档是xlsx')
                data = pd.read_excel(f'{now_path}\\static\\uploads\\{today}_{file.filename}')
                need = data.shape
                xlsx_list = []
                for line in range(need[0]):
                    xlsx_list.append(f"{data['姓名'][line]} {data['获奖等级'][line]}")

            # 调用批量生成函数
            if temp == 0:
                for demo in txt_list:
                    poster_name(demo)
            elif temp == 1:
                for demo in csv_list:
                    poster_name(demo)
            elif temp == 2:
                for demo in xlsx_list:
                    poster_name(demo)

            # 压缩
            zip_file_path(f'{now_path}\\static\\uploads\\{dir_name}',
                          f'{now_path}\\static\\uploads', f'{dir_name}.zip')
            # 发邮件
            send_listing(user_email)
            # 跳到提示界面
            return redirect('/index/success.html')


@app.route('/login/new.html', methods=['GET', 'POST'])
def new():
    if request.method == 'GET':
        return render_template('login/new.html')
    else:
        # 获取新建的用户信息
        new_user = request.form.get('user')
        new_pwd = request.form.get('pwd')

        # 建立连接，写入信息
        conn = pymysql.connect(host='localhost', port=3306, user='root', password='123', db='bcgs_db')  # 建立连接
        cur = conn.cursor()
        sql = 'INSERT INTO ' + 'accountinfo ' + 'VALUES(%s, %s)' % (new_user, new_pwd)
        cur.execute(sql)
        # 执行插入，不然不会插入
        conn.commit()
        
        cur.close()  # 关闭
        conn.close()

        # 更新数据
        global user_info
        user_info = get_user_info('bcgs_db', 'root', '123', 'accountInfo')
        return redirect('/')


@app.route('/logout')
def logout():
    del session['user_info']
    return redirect('/')


@app.route('/index/about.html')
def about():
    return render_template('index/about.html')


@app.route('/index/standard.html')
def standard():
    return render_template('index/standard.html')


@app.route('/index/update.html')
def update():
    return render_template('index/update.html')


@app.route('/index/success.html')
def success():
    return render_template('index/success.html')


if __name__ == '__main__':
    jpg_generate()
    app.run()
